/**
 * FormFieldTreeCheck
 * zTree API官网：https://treejs.cn/v3/api.php
 */
layui.define(['FormField', 'FormFieldActions', 'yunj', 'jquery'], function (exports) {

    let FormField = layui.FormField;
    let FormFieldActions = layui.FormFieldActions;
    let win = window;
    let doc = document;
    let $ = layui.jquery;

    class FormFieldTreeCheck extends FormField {

        constructor(options = {}) {
            super(options);
            this.mode = null;                  // 模式

            this.closeLevel = null;
            this.nodes = null;
            this.ztreeEl = null;
            this.ztree = null;
            this.itemsBoxEl = null;
            this.selectPopupContentEl = null;
        }

        // 处理节点
        handleArgsByNodes(args) {
            let that = this;
            let nodes = args.nodes;
            if (nodes.length <= 0) {
                return;
            }
            // hasSub 是否有子节点
            if (!nodes[0].hasOwnProperty('hasSub')) {
                for (let i = 0; i < nodes.length; i++) {
                    let node = nodes[i];
                    let hasSub = false;
                    for (let j = 0; j < nodes.length; j++) {
                        let otherNode = nodes[j];
                        if (otherNode.pid === node.id) {
                            hasSub = true;
                            break;
                        }
                    }
                    node.hasSub = hasSub;
                    nodes[i] = node;
                }
            }
            let nodeIdIdxMap = {};
            // nocheck 是否不可选
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];
                nodeIdIdxMap[node.id] = i;
                if (node.hasOwnProperty('nocheck')) {
                    continue;
                }
                if (args.lastChecked) {
                    // 最后一级可选
                    node.nocheck = node.hasSub
                } else {
                    // 全部可选
                    node.nocheck = false
                }
            }
            // full_name
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];
                if (node.full_name === "") {
                    node.full_name = that.getNodeFullName(node,nodeIdIdxMap,nodes);
                }
            }
            args.nodes = nodes;
        }

        getNodeFullName(node,nodeIdIdxMap,nodes) {
            let that = this;
            let fullName = node.name;
            if (nodeIdIdxMap.hasOwnProperty(node.pid)) {
                let parentNodeIdx = nodeIdIdxMap[node.pid];
                let parentNode = nodes[parentNodeIdx];
                if (parentNode) {
                    fullName = that.getNodeFullName(parentNode,nodeIdIdxMap,nodes) + " / " + fullName;
                }
            }
            return fullName;
        }

        // 获取允许的节点ids
        getArgsAllowNodeIds(args) {
            let that = this;
            let nodes = args.nodes;
            let allowNodeIds = [];
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];
                if (!(node.nocheck ?? false) && !(node.readonly ?? false)) {
                    allowNodeIds.push(node.id);
                }
            }
            return allowNodeIds;
        }

        defineBoxHtml() {
            let that = this;
            return `<div class="layui-form-item yunj-form-item yunj-form-tree" id="${that.id}">__layout__</div>`;
        }

        ztreeHtml() {
            let that = this;
            return `<ul id="${that.id}_ztree" class="ztree"></ul>`;
        }

        layoutControl() {
            let that = this;
            return `<div class="layui-input-inline yunj-form-item-control"><div class="show-box"><div class="items-box"></div></div></div>`;
        }

        async renderBefore() {
            let that = this;
            that.closeLevel = that.args.closeLevel;
            that.setCheckNodes();
            if (!win.hasOwnProperty('jQuery')) {
                win.jQuery = $;
            }
            await yunj.includeCss('/static/yunj/libs/zTree_v3/css/metroStyle/metroStyle.css');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.core.js');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.excheck.js');
            await yunj.includeJs('/static/yunj/libs/zTree_v3/js/jquery.ztree.exedit.js');
            return 'done';
        }

        // 获取节点等级
        getNodeLevel(nodeId, nodes) {
            let that = this;
            let nodeIdxMap = that.nodeIdxMap;
            if (!nodeIdxMap.has(nodeId)) return 0;
            let idx = nodeIdxMap.get(nodeId);
            let node = nodes[idx];
            if (node.hasOwnProperty("level")) return node.level;
            if (!node.pid || node.pid === "0")
                node.level = 1;
            else
                node.level = that.getNodeLevel(node.pid, nodes) + 1;
            return node.level;
        }

        // 设置可选节点
        setCheckNodes() {
            let that = this;
            let nodes = that.args.nodes;
            let nodeMap = new Map();
            let l = nodes.length;
            for (let i = 0; i < l; i++) {
                let node = nodes[i];
                let id = node.id;
                nodeMap.set(id, i);
                // 是否只读
                if (node.hasOwnProperty('readonly') && node.readonly) {
                    nodes[i].chkDisabled = true;
                }
                // 展开
                nodes[i].open = true;
                // 设置可选节点的子节点ids
                that.setCheckNodeChildIdsAttr(nodes, node);
            }
            that.nodeIdxMap = nodeMap;
            // 判断是否收起 closeLevel
            if (that.closeLevel > 0) {
                nodes.forEach(node => {
                    let nodeLevel = that.getNodeLevel(node.id, nodes);
                    node.open = nodeLevel < that.closeLevel;
                });
            }
            that.nodes = nodes;
        }

        // 设置可选节点的子节点ids
        setCheckNodeChildIdsAttr(nodes, node) {
            let that = this;
            if (!node.hasOwnProperty("childIds")) {
                let childIdsValue = [];
                for (let i = 0; i < nodes.length; i++) {
                    if (node.id === nodes[i].pid) {
                        childIdsValue.push(nodes[i].id);
                        if (!nodes[i].hasOwnProperty("childIds")) {
                            that.setCheckNodeChildIdsAttr(nodes, nodes[i]);
                        }
                        childIdsValue = childIdsValue.concat(nodes[i].childIds);
                    }
                }
                node.childIds = childIdsValue;
            }
        }

        renderDone() {
            let that = this;
            that.itemsBoxEl = that.boxEl.find('.show-box .items-box');
            // 设置字段操作项：内容清理、选择弹窗
            that.fieldActions = new FormFieldActions({
                fieldObj: that,
                fieldValueElSelector: `.show-box>.items-box`,
                actions: {
                    contentClear: null,
                    selectPopup: {
                        contentHtml: that.getSelectPopupContentHtml,
                        showAfter: that.renderTree,
                    },
                }
            });
            that.selectPopupContentEl = that.fieldActions.getActionObj('selectPopup').selectContentEl;
        }

        // 获取选择弹窗内容html
        getSelectPopupContentHtml = (data) => {
            let that = this;
            return new Promise((resolve, reject) => {
                let contentHtml = null;
                if (!that.ztreeEl) {
                    contentHtml = that.ztreeHtml();
                }
                resolve(contentHtml);
            });
        }

        async setValue(val = '') {
            let that = this;
            if (yunj.isScalar(val) && val)
                val = that.mode === "radio" ? [val]
                    : (yunj.isJson(val) ? JSON.parse(val) : (yunj.isString(val) && val.indexOf(",") !== -1 ? val.split(",") : [val]));
            val = yunj.isArray(val) ? val : [];
            let ids = JSON.parse(JSON.stringify(val));

            let itemsContent = '';
            for (let i = 0, l = ids.length; i < l; i++) {
                let id = ids[i];
                if (!that.nodeIdxMap.has(id)) continue;
                let idx = that.nodeIdxMap.get(id);
                let node = that.nodes[idx];
                if (node.nocheck ?? false) continue;
                let remove = that.args.readonly ? '' : '<i class="layui-icon layui-icon-close-fill item-remove" title="删除"></i>';
                itemsContent += `<div class="item" data-id="${id}" data-node='${JSON.stringify(node)}'>
                                    <span class="txt" title="${node.full_name}">${node.name}</span>
                                    ${remove}
                                </div>`;
            }
            that.itemsBoxEl.html(itemsContent);
            // 设置节点选中状态
            that.setTreeNodesChecked();
        }

        getValue() {
            let that = this;

            let itemsEl = that.itemsBoxEl.find('.item');
            if (itemsEl.length <= 0) return "";

            let val = [];
            itemsEl.each(function () {
                let id = $(this).data('node').id;
                val.push(id);
            });
            if (val.length <= 0) return "";
            return that.mode === 'radio' ? val[0] : val;
        }

        // 渲染可选模式的选择树
        renderTree = () => {
            let that = this;
            that.initZtree();
            // 设置节点选中状态
            that.setTreeNodesChecked();
        }

        // 设置树节点选中状态
        setTreeNodesChecked() {
            let that = this;
            let ztree = that.ztree;
            if (!ztree) return;
            // 取消之前选中的
            let checkNodes = that.ztree.getCheckedNodes(true);
            checkNodes.forEach((checkNode) => {
                // 只修改此节点勾选状态，无父子节点联动操作，不触发事件回调函数
                ztree.checkNode(checkNode, false, false, false);
            });
            // 设置当前需要选中的
            let ids = that.getValue();
            if (ids.length <= 0) {
                return;
            }
            if (!yunj.isArray(ids)) {
                ids = [ids];
            }
            ids.forEach((id) => {
                let node = ztree.getNodeByParam("id", id);
                if (!node) return;
                // 只修改此节点勾选状态，无父子节点联动操作，不触发事件回调函数
                ztree.checkNode(node, true, false, false);
            });
        }

        // 初始化可选模式的树ztree
        initZtree() {
            let that = this;
            if (that.ztree) return that.ztree;
            if (!that.ztreeEl) {
                that.ztreeEl = that.boxEl.find(`#${that.id}_ztree`);
            }
            let setting = {
                view: {
                    showIcon: false,
                },
                check: {
                    enable: true,
                    chkStyle: that.mode,
                },
                data: {
                    key: {
                        name: "name",
                        title:"full_name",
                    },
                    simpleData: {
                        enable: true,
                        idKey: "id",
                        pIdKey: "pid",
                    }
                },
                edit: {
                    enable: true,
                    showRemoveBtn: false,
                    showRenameBtn: false
                },
                callback: {
                    onClick: function (e, treeId, tree_node, clickFlag) {
                        that.ztree.checkNode(tree_node, !tree_node.checked, true);
                        let nodes = that.ztree.getCheckedNodes(true);
                        let val = [];
                        for (let i = 0; i < nodes.length; i++) {
                            val.push(nodes[i].id);
                        }
                        that.setValue(val);
                        // 触发change事件
                        that.outermostEl.trigger(`yunj_form_${that.id}_change`, [that]);
                    },
                    onCheck: function (e, treeId, tree_node) {
                        let nodes = that.ztree.getCheckedNodes(true);
                        let val = [];
                        for (let i = 0; i < nodes.length; i++) {
                            val.push(nodes[i].id);
                        }
                        that.setValue(val);
                        // 触发change事件
                        that.outermostEl.trigger(`yunj_form_${that.id}_change`, [that]);
                    },
                }
            };
            switch (that.mode) {
                case "radio":
                    setting.check.chkStyle = "radio";
                    setting.check.radioType = "all";
                    break;
                case "checkbox":
                    // 父子关联关系 check.chkboxType = { "Y" : "ps", "N" : "ps" }
                    // 勾选时关联父,勾选时关联子,取消勾选时关联父,取消勾选时关联子
                    let [checkedParent, checkedChild, uncheckedParent, uncheckedChild] = that.args.correlation
                    let chkboxTypeY = "",chkboxTypeN = "";
                    if (checkedParent) chkboxTypeY += "p";
                    if (checkedChild) chkboxTypeY += "s";
                    if (uncheckedParent) chkboxTypeN += "p";
                    if (uncheckedChild) chkboxTypeN += "s";
                    setting.check.chkboxType = {"Y" : chkboxTypeY, "N" : chkboxTypeN};
                    break;
            }
            that.ztree = $.fn.zTree.init(that.ztreeEl, setting, that.nodes);
            return that.ztree;
        }

        defineExtraEventBind() {
            let that = this;

            that.boxEl.on('click', '.item-remove', function (e) {
                if (that.args.readonly) return false;
                let itemEl = $(this).parent(".item");
                let id = itemEl.data("node").id;
                let nodeIdx = that.nodeIdxMap.get(id);
                let node = that.nodes[nodeIdx];
                let delIds = [id];
                // 判断是否删除子节点
                if (that.mode == "checkbox") {
                    // 判断取消选中是否关联子节点
                    let uncheckedChild = that.args.correlation[3];
                    if (uncheckedChild) {
                        delIds = delIds.concat(node.childIds);
                    }
                } else {
                    delIds = delIds.concat(node.childIds);
                }
                let isSelectPopupShow = that.selectPopupContentEl.is(':visible');
                delIds.forEach((delId) => {
                    // 删除节点
                    let delItemEl = that.itemsBoxEl.find(`[data-id="${delId}"]`);
                    if (delItemEl.length > 0) {
                        delItemEl.remove();
                    }
                    if (isSelectPopupShow) {
                        let ztreeNode = that.ztree.getNodeByParam("id", id);
                        if (!ztreeNode) return;
                        // 只修改此节点勾选状态，无父子节点联动操作，不触发事件回调函数
                        that.ztree.checkNode(ztreeNode, false, false, false);
                    }
                });
                e.stopPropagation();
                // 触发change事件
                that.outermostEl.trigger(`yunj_form_${that.id}_change`, [that]);
            });

        }

    }

    exports('FormFieldTreeCheck', FormFieldTreeCheck);
});